﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Media3D;
using Eniux.Windows.ThreeDEngine.Base.CameraControllers;
using System.Windows.Input;
using System.Diagnostics;
using System.Windows.Documents;
using System.Windows.Media;
using Eniux.Windows.ThreeDEngine.Helper;
using Eniux.Windows.ThreeDEngine.Adorners;
using Eniux.Windows.ThreeDEngine.AttachObject;

namespace Eniux.Windows.ThreeDEngine.Base.CameraControllers
{
    /// <summary>
    /// A control that manipulates the camera by mouse and keyboard gestures.
    /// </summary>
    public class CameraController : Grid
    {

        #region 注册属性

        #region IsChangeFieldOfViewEnabled（）
        /// <summary>
        ///   Gets or sets a value indicating whether field of view can be changed.
        /// </summary>
        public bool IsChangeFieldOfViewEnabled
        {
            get
            {
                return (bool)this.GetValue(IsChangeFieldOfViewEnabledProperty);
            }

            set
            {
                this.SetValue(IsChangeFieldOfViewEnabledProperty, value);
            }
        }

        /// <summary>
        ///   The is change fov enabled property.
        /// </summary>
        public static readonly DependencyProperty IsChangeFieldOfViewEnabledProperty =
            DependencyProperty.Register(
                "IsChangeFieldOfViewEnabled", typeof(bool), typeof(CameraController), new UIPropertyMetadata(true));
        #endregion

        #region Camera（相机）
        /// <summary>
        ///  获取或设置相机
        /// </summary>
        public ProjectionCamera Camera
        {
            get { return (ProjectionCamera)this.GetValue(CameraProperty); }
            set { this.SetValue(CameraProperty, value); }
        }
        /// <summary>
        ///  相机
        /// </summary>
        public static readonly DependencyProperty CameraProperty = DependencyProperty.Register(
            "Camera",
            typeof(ProjectionCamera),
            typeof(CameraController),
            new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, CameraChanged));

        private static void CameraChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((CameraController)d).OnCameraChanged();
        }

        private void OnCameraChanged()
        {
            this.CameraHistory.Clear();
            this.PushCameraSetting();
        }
        #endregion

        #region SpinReleaseTime
        /// <summary>
        /// 
        /// </summary>
        public int SpinReleaseTime
        {
            get { return (int)this.GetValue(SpinReleaseTimeProperty); }
            set { this.SetValue(SpinReleaseTimeProperty, value); }
        }
        /// <summary>
        ///   The spin release time property.
        /// </summary>
        public static readonly DependencyProperty SpinReleaseTimeProperty =
            DependencyProperty.Register(
                "SpinReleaseTime", typeof(int), typeof(CameraController), new UIPropertyMetadata(200));
        #endregion

        #region Enabled（是否可用）
        /// <summary>
        ///  获取或设置是否可用
        /// </summary>
        public bool Enabled
        {
            get { return (bool)this.GetValue(EnabledProperty); }
            set { this.SetValue(EnabledProperty, value); }
        }

        /// <summary>
        ///  是否可用
        /// </summary>
        public static readonly DependencyProperty EnabledProperty = DependencyProperty.Register(
            "Enabled", typeof(bool), typeof(CameraController), new UIPropertyMetadata(true));
        #endregion

        #region Viewport（3D视窗）
        /// <summary>
        ///  获取或设置3D视窗
        /// </summary>
        public Viewport3D Viewport
        {
            get { return (Viewport3D)this.GetValue(ViewportProperty); }
            set { this.SetValue(ViewportProperty, value); }
        }

        /// <summary>
        ///  3D视窗属性
        /// </summary>
        public static readonly DependencyProperty ViewportProperty = DependencyProperty.Register(
            "Viewport", typeof(Viewport3D), typeof(CameraController), new PropertyMetadata(null, ViewportChanged));
        /// <summary>
        /// 视窗改变调用该方法
        /// </summary>
        /// <param name="d"></param>
        /// <param name="e"></param>
        private static void ViewportChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((CameraController)d).OnViewportChanged();
        }

        /// <summary>
        /// The on viewport changed.
        /// </summary>
        private void OnViewportChanged()
        {
        }
        #endregion

        #region TouchMode（触摸模式）
        /// <summary>
        /// 获取或设置触摸模式
        /// </summary>
        public TouchMode TouchMode
        {
            get { return (TouchMode)this.GetValue(TouchModeProperty); }
            set { this.SetValue(TouchModeProperty, value); }
        }

        /// <summary>
        /// 触摸模式属性
        /// </summary>
        public static readonly DependencyProperty TouchModeProperty = DependencyProperty.Register(
            "TouchMode", typeof(TouchMode), typeof(CameraController), new UIPropertyMetadata(TouchMode.Panning));
        #endregion  
        #endregion

        #region 私有变量
        /// <summary>
        /// 
        /// </summary>
        private readonly Stopwatch spinWatch = new Stopwatch();

        /// <summary>
        /// 表
        /// </summary>
        private readonly Stopwatch watch = new Stopwatch();

        /// <summary>
        ///   The is spinning flag.
        /// </summary>
        private bool isSpinning;

        /// <summary>
        ///  最后一次滴答
        /// </summary>
        private long lastTick;

        /// <summary>
        ///  平移速度
        /// </summary>
        private Vector3D panSpeed;

        /// <summary>
        ///  旋转速度
        /// </summary>
        private Vector rotationSpeed;

        /// <summary>
        ///   The spinning speed.
        /// </summary>
        private Vector spinningSpeed;

        /// <summary>
        ///  目标装饰器
        /// </summary>
        private Adorner targetAdorner;

        /// <summary>
        ///  矩形装饰器
        /// </summary>
        private RectangleAdorner rectangleAdorner;

        /// <summary>
        ///   缩放速度
        /// </summary>
        private double zoomSpeed;

        /// <summary>
        /// 触摸点
        /// </summary>
        private Point touchDownPoint;

        /// <summary>
        /// 旋转3D点
        /// </summary>
        private Point3D spinningPoint3D;

        /// <summary>
        /// 旋转位置
        /// </summary>
        private Point spinningPosition;

        /// <summary>
        ///  旋转位置
        /// </summary>
        private Point rotationPosition;

        /// <summary>
        /// 旋转3D点
        /// </summary>
        private Point3D rotationPoint3D;

        /// <summary>
        /// 缩放3D点
        /// </summary>
        private Point3D zoomPoint3D;

        /// <summary>
        /// 相机历史记录
        /// </summary>
        private readonly List<CameraSetting> CameraHistory = new List<CameraSetting>();
        #endregion

        #region 构造 、析构
        /// <summary>
        /// 静态构造函数
        /// </summary>
        static CameraController()
        {
            BackgroundProperty.OverrideMetadata(
                typeof(CameraController), new FrameworkPropertyMetadata(Brushes.Transparent));
            FocusVisualStyleProperty.OverrideMetadata(typeof(CameraController), new FrameworkPropertyMetadata(null));
            AttachCamera.AddOwner(typeof(CameraController));
        }

        /// <summary>
        /// 默认构造函数
        /// </summary>
        public CameraController()
        {
            this.Loaded += this.CameraControllerLoaded;
            this.Unloaded += this.CameraControllerUnloaded;

            // Must be focusable to received key events
            this.Focusable = true;
            this.FocusVisualStyle = null;

            this.IsManipulationEnabled = true;

            this.watch.Start();
            this.lastTick = this.watch.ElapsedTicks;
            this.InitializeBindings();
            Touch.FrameReported += new TouchFrameEventHandler(Touch_FrameReported);
        }

        private TouchPoint primaryTouchPoint;
        private TouchPoint secondTouchPoint;
        private double length = 0;
        private double _primaryX = 0, _primaryY = 0, _secondX = 0, _secondY = 0;
        private double originlength = 0;
        void Touch_FrameReported(object sender, TouchFrameEventArgs e)
        {
                switch (e.GetTouchPoints(this).Count)
                {
                    case 1:
                        TouchMode = TouchMode.Rotating;
                        break;
                    case 2:
                        {
                            foreach (TouchPoint tp in e.GetTouchPoints(this))
                            {
                                if (e.GetPrimaryTouchPoint(this)!=null&&tp.TouchDevice.Id == e.GetPrimaryTouchPoint(this).TouchDevice.Id)
                                {
                                    if (primaryTouchPoint == null)
                                    {
                                        primaryTouchPoint = tp;
                                    }
                                    else
                                    {
                                        _primaryX += tp.Position.X - primaryTouchPoint.Position.X;
                                        _primaryY += tp.Position.Y - primaryTouchPoint.Position.Y;
                                        primaryTouchPoint = tp;
                                    }
                                }
                                else
                                {
                                    if (secondTouchPoint == null)
                                    {
                                        secondTouchPoint = tp;
                                    }
                                    else
                                    {
                                        _secondX += tp.Position.X - secondTouchPoint.Position.X;
                                        _secondY += tp.Position.Y - secondTouchPoint.Position.Y;
                                        secondTouchPoint = tp;
                                    }
                                }
                            }
                            if (primaryTouchPoint != null && secondTouchPoint != null && originlength == 0)
                            {
                                originlength = Math.Sqrt(Math.Pow(primaryTouchPoint.Position.X - secondTouchPoint.Position.X, 2) + Math.Pow(primaryTouchPoint.Position.Y - secondTouchPoint.Position.Y, 2));
                            }
                            if (_primaryX * _secondX > 0 && _primaryY * _secondY > 0)
                            {
                                TouchMode = TouchMode.Panning;
                            }
                            if (_primaryX * _secondX < 0&& _primaryY * _secondY < 0)
                            {
                                TouchMode = TouchMode.Zooming;
                                length = originlength - Math.Sqrt(Math.Pow(primaryTouchPoint.Position.X - secondTouchPoint.Position.X, 2) + Math.Pow(primaryTouchPoint.Position.Y - secondTouchPoint.Position.Y, 2));
                            }
                            break;
                        }
                    default:
                        break;
                } 
        } 
        #endregion

        #region 操作句柄
        /// <summary>
        ///   改变观察事件句柄
        /// </summary>
        private RotateHandler changeLookAtHandler;

        /// <summary>
        ///   旋转事件句柄
        /// </summary>
        private RotateHandler rotateHandler;

        /// <summary>
        /// 矩形缩放事件句柄
        /// </summary>
        private ZoomRectangleHandler zoomRectangleHandler;

        /// <summary>
        ///  缩放事件句柄
        /// </summary>
        private ZoomHandler zoomHandler;

        /// <summary>
        ///   改变。。事件句柄
        /// </summary>
        private ZoomHandler changeFieldOfViewHandler;

        /// <summary>
        ///  平移事件句柄
        /// </summary>
        private PanHandler panHandler; 
        #endregion

        #region 操作命令
        /// <summary>
        ///  旋转命令
        /// </summary>
        public static RoutedCommand RotateCommand = new RoutedCommand();

        /// <summary>
        ///  平移命令
        /// </summary>
        public static RoutedCommand PanCommand = new RoutedCommand();

        /// <summary>
        ///  缩放命令
        /// </summary>
        public static RoutedCommand ZoomCommand = new RoutedCommand();

        /// <summary>
        ///   矩形缩放命令
        /// </summary>
        public static RoutedCommand ZoomRectangleCommand = new RoutedCommand();

        /// <summary>
        /// 缩放命令
        /// </summary>
        public static RoutedCommand ZoomExtentsCommand = new RoutedCommand();

        /// <summary>
        ///   The change fov command.
        /// </summary>
        public static RoutedCommand ChangeFieldOfViewCommand = new RoutedCommand();

        /// <summary>
        ///  重置相机命令
        /// </summary>
        public static RoutedCommand ResetCameraCommand = new RoutedCommand();

        /// <summary>
        ///  改变观看命令
        /// </summary>
        public static RoutedCommand ChangeLookAtCommand = new RoutedCommand();

        /// <summary>
        ///  顶视图命令
        /// </summary>
        public static RoutedCommand TopViewCommand = new RoutedCommand();

        /// <summary>
        /// 底视图命令
        /// </summary>
        public static RoutedCommand BottomViewCommand = new RoutedCommand();

        /// <summary>
        ///  左视图命令
        /// </summary>
        public static RoutedCommand LeftViewCommand = new RoutedCommand();

        /// <summary>
        ///  右视图命令
        /// </summary>
        public static RoutedCommand RightViewCommand = new RoutedCommand();

        /// <summary>
        ///   前视图命令
        /// </summary>
        public static RoutedCommand FrontViewCommand = new RoutedCommand();

        /// <summary>
        ///  后视图命令
        /// </summary>
        public static RoutedCommand BackViewCommand = new RoutedCommand(); 
        #endregion

        /// <summary>
        /// 初始化输入绑定
        /// </summary>
        private void InitializeBindings()
        {
            this.changeLookAtHandler = new RotateHandler(this, true);
            this.rotateHandler = new RotateHandler(this);
            this.zoomRectangleHandler = new ZoomRectangleHandler(this);
            this.zoomHandler = new ZoomHandler(this);
            this.panHandler = new PanHandler(this);
            this.changeFieldOfViewHandler = new ZoomHandler(this, true);

            this.CommandBindings.Add(new CommandBinding(PanCommand, this.panHandler.Execute));
            this.CommandBindings.Add(new CommandBinding(RotateCommand, this.rotateHandler.Execute));
            this.CommandBindings.Add(new CommandBinding(ZoomCommand, this.zoomHandler.Execute));
            this.CommandBindings.Add(new CommandBinding(ZoomRectangleCommand, this.zoomRectangleHandler.Execute));
            this.CommandBindings.Add(new CommandBinding(ZoomExtentsCommand, this.ZoomExtentsHandler));
            this.CommandBindings.Add(new CommandBinding(ResetCameraCommand, this.ResetCameraHandler));
            this.CommandBindings.Add(new CommandBinding(ChangeLookAtCommand, this.changeLookAtHandler.Execute));
            this.CommandBindings.Add(new CommandBinding(ChangeFieldOfViewCommand, this.changeFieldOfViewHandler.Execute));

            this.CommandBindings.Add(new CommandBinding(TopViewCommand, this.TopViewHandler));
            this.CommandBindings.Add(new CommandBinding(BottomViewCommand, this.BottomViewHandler));
            this.CommandBindings.Add(new CommandBinding(LeftViewCommand, this.LeftViewHandler));
            this.CommandBindings.Add(new CommandBinding(RightViewCommand, this.RightViewHandler));
            this.CommandBindings.Add(new CommandBinding(FrontViewCommand, this.FrontViewHandler));
            this.CommandBindings.Add(new CommandBinding(BackViewCommand, this.BackViewHandler));
        }

        #region ViewBox操作
        /// <summary>
        /// 顶视图事件处理程序
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void TopViewHandler(object sender, ExecutedRoutedEventArgs e)
        {
            this.ChangeDirection(new Vector3D(0, 0, -1), new Vector3D(0, 1, 0));
        }

        /// <summary>
        /// 底视图事件处理程序
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void BottomViewHandler(object sender, ExecutedRoutedEventArgs e)
        {
            this.ChangeDirection(new Vector3D(0, 0, 1), new Vector3D(0, -1, 0));
        }

        /// <summary>
        /// 左视图事件处理程序
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void LeftViewHandler(object sender, ExecutedRoutedEventArgs e)
        {
            this.ChangeDirection(new Vector3D(0, 1, 0), new Vector3D(0, 0, 1));
        }

        /// <summary>
        /// 右视图事件处理程序
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void RightViewHandler(object sender, ExecutedRoutedEventArgs e)
        {
            this.ChangeDirection(new Vector3D(0, -1, 0), new Vector3D(0, 0, 1));
        }

        /// <summary>
        /// 前视图事件处理程序
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void FrontViewHandler(object sender, ExecutedRoutedEventArgs e)
        {
            this.ChangeDirection(new Vector3D(-1, 0, 0), new Vector3D(0, 0, 1));
        }

        /// <summary>
        /// 后视图事件处理程序
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void BackViewHandler(object sender, ExecutedRoutedEventArgs e)
        {
            this.ChangeDirection(new Vector3D(1, 0, 0), new Vector3D(0, 0, 1));
        }

        /// <summary>
        /// 改变相机方向
        /// </summary>
        /// <param name="lookDir"></param>
        /// <param name="upDir"></param>
        /// <param name="animationTime"></param>
        public void ChangeDirection(Vector3D lookDir, Vector3D upDir, double animationTime = 500)
        {
            this.StopAnimations();
            this.PushCameraSetting();
            CameraHelper.ChangeDirection(this.ActualCamera, lookDir, upDir, animationTime);
        }

        /// <summary>
        /// 改变相机方向
        /// </summary>
        /// <param name="lookDir"></param>
        /// <param name="animationTime"></param>
        public void ChangeDirection(Vector3D lookDir, double animationTime = 500)
        {
            this.StopAnimations();
            this.PushCameraSetting();
            CameraHelper.ChangeDirection(this.ActualCamera, lookDir, this.ActualCamera.UpDirection, animationTime);
        }
        #endregion

        #region 触摸操作
        /// <summary>
        ///ManipulationStarted事件
        /// </summary>
        /// <param name="e"></param>
        protected override void OnManipulationStarted(ManipulationStartedEventArgs e)
        {
            base.OnManipulationStarted(e);
            this.Focus();
            this.touchDownPoint = e.ManipulationOrigin;
            this.panHandler.Started(new ManipulationEventArgs(this.touchDownPoint));
            this.rotateHandler.Started(new ManipulationEventArgs(this.touchDownPoint));
            this.zoomHandler.Started(new ManipulationEventArgs(this.touchDownPoint));
            e.Handled = true;
        }


        /// <summary>
        /// ManipulationDelta事件
        /// </summary>
        /// <param name="e"></param>
        protected override void OnManipulationDelta(ManipulationDeltaEventArgs e)
        {
            base.OnManipulationDelta(e);

            // http://msdn.microsoft.com/en-us/library/system.windows.uielement.manipulationdelta.aspx

            // Debug.WriteLine("OnManipulationDelta: T={0}, S={1}, R={2}, O={3}", e.DeltaManipulation.Translation, e.DeltaManipulation.Scale, e.DeltaManipulation.Rotation, e.ManipulationOrigin);
            Point position = this.touchDownPoint + e.CumulativeManipulation.Translation;

            switch (this.TouchMode)
            {
                case TouchMode.Panning:
                    this.panHandler.Delta(new ManipulationEventArgs(position));
                    break;
                case TouchMode.Rotating:
                    this.rotateHandler.Delta(new ManipulationEventArgs(position));
                    break;
                case TouchMode.Zooming:
                    {
                        if (length > 0)
                        {
                            this.AddZoomForce(-(-120) * 0.001);
                        }
                        else
                        {
                            this.AddZoomForce(-(120) * 0.001);
                        }
                        break;
                    }
            }
            e.Handled = true;
        }

        /// <summary>
        /// ManipulationCompleted事件
        /// </summary>
        /// <param name="e"></param>
        protected override void OnManipulationCompleted(ManipulationCompletedEventArgs e)
        {
            base.OnManipulationCompleted(e);
            Point p = this.touchDownPoint + e.TotalManipulation.Translation;

            switch (this.TouchMode)
            {
                case TouchMode.Panning:
                    this.panHandler.Completed(new ManipulationEventArgs(p));
                    break;
                case TouchMode.Rotating:
                    this.rotateHandler.Completed(new ManipulationEventArgs(p));
                    break;
                case TouchMode.Zooming:
                    if (!AttachCamera.GetIsZoomEnabled(this))
                    {
                        return;
                    }
                    this.zoomHandler.Completed(new ManipulationEventArgs(p));
                    break;
            }
            length = 0;
            primaryTouchPoint = null;
            secondTouchPoint = null;
            _primaryX = 0;
            _primaryY = 0;
            _secondX = 0; 
            _secondY = 0;
            originlength =0;
            e.Handled = true;
        }

        /// <summary>
        /// ManipulationInertiaStarting事件
        /// </summary>
        /// <param name="e"></param>
        protected override void OnManipulationInertiaStarting(ManipulationInertiaStartingEventArgs e)
        {
            base.OnManipulationInertiaStarting(e);           
        }

        /// <summary>
        /// StylusSystemGestures事件
        /// </summary>
        /// <param name="e"></param>
        protected override void OnStylusSystemGesture(StylusSystemGestureEventArgs e)
        {
            base.OnStylusSystemGesture(e);
            if (e.SystemGesture == SystemGesture.HoldEnter)
            {
                Point p = e.GetPosition(this);
                this.changeLookAtHandler.Started(new ManipulationEventArgs(p));
                this.changeLookAtHandler.Completed(new ManipulationEventArgs(p));
                e.Handled = true;
            }

            if (e.SystemGesture == SystemGesture.TwoFingerTap)
            {
                this.ZoomExtents();
                e.Handled = true;
            }
        }

        /// <summary>
        /// TouchDown事件
        /// </summary>
        /// <param name="e"></param>
        protected override void OnTouchDown(TouchEventArgs e)
        {
            base.OnTouchDown(e);
        }
        #endregion

        #region 键盘操作
        /// <summary>
        /// 键盘事件调用该方法
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnKeyDown(object sender, KeyEventArgs e)
        {
            this.OnKeyDown(e);
            bool shift = Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift);
            bool control = Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl);
            double f = control ? 0.25 : 1;

            if (!shift)
            {
                switch (e.Key)
                {
                    case Key.Left:
                        this.AddRotateForce(-1 * f, 0);
                        e.Handled = true;
                        break;
                    case Key.Right:
                        this.AddRotateForce(1 * f, 0);
                        e.Handled = true;
                        break;
                    case Key.Up:
                        this.AddRotateForce(0, -1 * f);
                        e.Handled = true;
                        break;
                    case Key.Down:
                        this.AddRotateForce(0, 1 * f);
                        e.Handled = true;
                        break;
                }
            }
            else
            {
                switch (e.Key)
                {
                    case Key.Left:
                        this.AddPanForce(-5 * f, 0);
                        e.Handled = true;
                        break;
                    case Key.Right:
                        this.AddPanForce(5 * f, 0);
                        e.Handled = true;
                        break;
                    case Key.Up:
                        this.AddPanForce(0, -5 * f);
                        e.Handled = true;
                        break;
                    case Key.Down:
                        this.AddPanForce(0, 5 * f);
                        e.Handled = true;
                        break;
                }
            }

            switch (e.Key)
            {
                case Key.PageUp:
                    this.AddZoomForce(-0.1 * f);
                    e.Handled = true;
                    break;
                case Key.PageDown:
                    this.AddZoomForce(0.1 * f);
                    e.Handled = true;
                    break;
                case Key.Back:
                    if (this.RestoreCameraSetting())
                    {
                        e.Handled = true;
                    }

                    break;
            }
        } 
        #endregion

        #region 鼠标操作
        /// <summary>
        /// 鼠标滚轮事件处理程序
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnMouseWheel(object sender, MouseWheelEventArgs e)
        {
            if (!AttachCamera.GetIsZoomEnabled(this))
            {
                return;
            }
            if (AttachCamera.GetZoomAroundMouseDownPoint(this))
            {

                Point point = e.GetPosition(this);
                Point3D nearestPoint;
                Vector3D normal;
                DependencyObject visual;
                if (Viewport3DHelper.FindNearest(this.Viewport, point, out nearestPoint, out normal, out visual))
                {
                    this.AddZoomForce(-e.Delta * 0.001, nearestPoint);
                    e.Handled = true;
                    return;
                }
            }

            this.AddZoomForce(-e.Delta * 0.001);
            e.Handled = true;
        }

        /// <summary>
        /// MouseDown事件
        /// </summary>
        /// <param name="e"></param>
        protected override void OnMouseDown(MouseButtonEventArgs e)
        {
            base.OnMouseDown(e);
            this.Focus();
            if (e.ChangedButton == MouseButton.XButton1)
            {
                this.RestoreCameraSetting();
            }
        } 
        #endregion

        #region 公共属性

        /// <summary>
        ///  获取当前相机
        /// </summary>
        public ProjectionCamera ActualCamera
        {
            get
            {
                if (this.Camera != null)
                {
                    return this.Camera;
                }

                if (this.Viewport != null)
                {
                    return this.Viewport.Camera as ProjectionCamera;
                }

                return null;
            }
        }

        /// <summary>
        ///   是否是透视相机
        /// </summary>
        protected bool IsPerspectiveCamera
        {
            get { return this.ActualCamera is PerspectiveCamera; }
        }

        /// <summary>
        /// 是否是正交相机
        /// </summary>
        protected bool IsOrthographicCamera
        {
            get { return this.ActualCamera is OrthographicCamera; }
        }

        /// <summary>
        ///   获取透视相机
        /// </summary>
        protected PerspectiveCamera PerspectiveCamera
        {
            get { return this.ActualCamera as PerspectiveCamera; }
        }

        /// <summary>
        /// 获取正交相机
        /// </summary>
        protected OrthographicCamera OrthographicCamera
        {
            get { return this.ActualCamera as OrthographicCamera; }
        }

        /// <summary>
        ///  相机观察方向
        /// </summary>
        public Vector3D CameraLookDirection
        {
            get { return this.ActualCamera.LookDirection; }
            set { this.ActualCamera.LookDirection = value; }
        }

        /// <summary>
        ///  获取或设置相机向上方向
        /// </summary>
        public Vector3D CameraUpDirection
        {
            get { return this.ActualCamera.UpDirection; }
            set { this.ActualCamera.UpDirection = value; }
        }

        /// <summary>
        ///   获取或设置相机位置
        /// </summary>
        public Point3D CameraPosition
        {
            get { return this.ActualCamera.Position; }
            set { this.ActualCamera.Position = value; }
        }

        /// <summary>
        /// 获取或设置相机目标
        /// </summary>
        public Point3D CameraTarget
        {
            get { return this.CameraPosition + this.CameraLookDirection; }
            set { this.CameraLookDirection = value - this.CameraPosition; }
        }

        /// <summary>
        /// 获取是否是激活的
        /// </summary>
        public bool IsActive
        {
            get { return this.Enabled && this.Viewport != null && this.ActualCamera != null; }
        } 
        #endregion

        #region 方法

        /// <summary>
        /// 相机Loaded时调用该方法
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void CameraControllerLoaded(object sender, RoutedEventArgs e)
        {
            this.SubscribeEvents();
        }

        /// <summary>
        /// 相机Unload时调用该方法
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void CameraControllerUnloaded(object sender, RoutedEventArgs e)
        {
            this.UnSubscribeEvents();
        }

        /// <summary>
        /// 缩放事件处理程序
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ZoomExtentsHandler(object sender, ExecutedRoutedEventArgs e)
        {
            this.StopAnimations();
            this.ZoomExtents();
        }

        /// <summary>
        /// 重置相机处理程序
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ResetCameraHandler(object sender, ExecutedRoutedEventArgs e)
        {
            this.StopAnimations();
            this.ResetCamera();
        }

        /// <summary>
        /// 停止动画
        /// </summary>
        private void StopAnimations()
        {
            this.rotationSpeed = new Vector();
            this.panSpeed = new Vector3D();
            this.zoomSpeed = 0;
        }

        /// <summary>
        /// 订阅事件
        /// </summary>
        private void SubscribeEvents()
        {
            this.MouseWheel += this.OnMouseWheel;
            this.KeyDown += this.OnKeyDown;
            CompositionTarget.Rendering += this.CompositionTargetRendering;
        }

        /// <summary>
        /// 撤消事件订阅
        /// </summary>
        private void UnSubscribeEvents()
        {
            this.MouseWheel -= this.OnMouseWheel;
            this.KeyDown -= this.OnKeyDown;
            CompositionTarget.Rendering -= this.CompositionTargetRendering;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void CompositionTargetRendering(object sender, EventArgs e)
        {
            // Time in seconds
            double time = 1.0 * (this.watch.ElapsedTicks - this.lastTick) / Stopwatch.Frequency;
            this.lastTick = this.watch.ElapsedTicks;
            this.OnTimeStep(time);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="time"></param>
        private void OnTimeStep(double time)
        {
            // should be independent of time
            double factor = Math.Pow(AttachCamera.GetInertiaFactor(this), time / 0.012);
            factor = this.Clamp(factor, 0.2, 1);

            if (this.isSpinning && this.spinningSpeed.LengthSquared > 0)
            {
                this.rotateHandler.Rotate(
                    this.spinningPosition, this.spinningPosition + this.spinningSpeed * time, this.spinningPoint3D);

                if (!AttachCamera.GetInfiniteSpin(this))
                {
                    this.spinningSpeed *= factor;
                }

                this.spinWatch.Reset();
                this.spinWatch.Start();
            }

            if (this.rotationSpeed.LengthSquared > 0.1)
            {
                this.rotateHandler.Rotate(
                    this.rotationPosition, this.rotationPosition + this.rotationSpeed * time, this.rotationPoint3D);
                this.rotationSpeed *= factor;
            }

            if (Math.Abs(this.panSpeed.LengthSquared) > 0.0001)
            {
                this.panHandler.Pan(this.panSpeed * time);
                this.panSpeed *= factor;
            }

            if (Math.Abs(this.zoomSpeed) > 0.1)
            {
                this.zoomHandler.Zoom(this.zoomSpeed * time, this.zoomPoint3D);
                this.zoomSpeed *= factor;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="factor"></param>
        /// <param name="min"></param>
        /// <param name="max"></param>
        /// <returns></returns>
        private double Clamp(double factor, double min, double max)
        {
            if (factor < min)
            {
                return min;
            }

            if (factor > max)
            {
                return max;
            }

            return factor;
        }

        /// <summary>
        /// 停止旋转
        /// </summary>
        public void StopSpin()
        {
            this.isSpinning = false;
        }

        /// <summary>
        /// 开始旋转
        /// </summary>
        /// <param name="speed">速度</param>
        /// <param name="position">位置</param>
        /// <param name="aroundPoint">围绕旋转的3D点</param>
        public void StartSpin(Vector speed, Point position, Point3D aroundPoint)
        {
            this.spinningSpeed = speed;
            this.spinningPosition = position;
            this.spinningPoint3D = aroundPoint;
            this.isSpinning = true;
            this.spinWatch.Reset();
            this.spinWatch.Start();
        }

        /// <summary>
        /// 重置相机
        /// </summary>
        public void ResetCamera()
        {
            if (!AttachCamera.GetIsPanEnabled(this) || !AttachCamera.GetIsRotationEnabled(this) || !AttachCamera.GetIsZoomEnabled(this))
            {
                return;
            }

            this.PushCameraSetting();
            CameraHelper.Reset(this.ActualCamera);
            CameraHelper.ZoomExtents(this.ActualCamera, this.Viewport);
        }

        /// <summary>
        /// 重置相机向上方向
        /// </summary>
        public void ResetCameraUpDirection()
        {
            this.CameraUpDirection = AttachCamera.GetModelUpDirection(this);
        }

        /// <summary>
        /// 推送相机设置到内部堆栈上
        /// </summary>
        public void PushCameraSetting()
        {
            this.CameraHistory.Add(new CameraSetting(this.ActualCamera));
            if (this.CameraHistory.Count > 100)
            {
                this.CameraHistory.RemoveAt(0);
            }
        }

        /// <summary>
        /// 恢复相机设置
        /// </summary>
        /// <returns></returns>
        public bool RestoreCameraSetting()
        {
            if (this.CameraHistory.Count > 0)
            {
                CameraSetting cs = this.CameraHistory[this.CameraHistory.Count - 1];
                this.CameraHistory.RemoveAt(this.CameraHistory.Count - 1);
                cs.UpdateCamera(this.ActualCamera);
                return true;
            }

            return false;
        }

        /// <summary>
        /// 按给定的增量缩放
        /// </summary>
        /// <param name="delta"></param>
        public void Zoom(double delta)
        {
            this.zoomHandler.Zoom(delta);
        }

        /// <summary>
        /// The Zoom extents.
        /// </summary>
        public void ZoomExtents()
        {
            if (!AttachCamera.GetIsZoomEnabled(this))
            {
                return;
            }
            this.PushCameraSetting();
            CameraHelper.ZoomExtents(this.ActualCamera, this.Viewport, 200);
        }

        /// <summary>
        /// 添加平移
        /// </summary>
        /// <param name="dx"></param>
        /// <param name="dy"></param>
        public void AddPanForce(double dx, double dy)
        {
            this.AddPanForce(this.FindPanVector(dx, dy));
        }

        /// <summary>
        /// 查找平移向量
        /// </summary>
        /// <param name="dx"></param>
        /// <param name="dy"></param>
        /// <returns></returns>
        private Vector3D FindPanVector(double dx, double dy)
        {
            Vector3D axis1 = Vector3D.CrossProduct(this.CameraLookDirection, this.CameraUpDirection);
            Vector3D axis2 = Vector3D.CrossProduct(axis1, this.CameraLookDirection);
            axis1.Normalize();
            axis2.Normalize();
            double l = this.CameraLookDirection.Length;
            double f = l * 0.001;
            Vector3D move = -axis1 * f * dx + axis2 * f * dy;

            // this should be dependent on distance to target?           
            return move;
        }

        /// <summary>
        /// 添加平移
        /// </summary>
        /// <param name="pan"></param>
        public void AddPanForce(Vector3D pan)
        {
            if (!AttachCamera.GetIsPanEnabled(this))
            {
                return;
            }
            this.PushCameraSetting();
            this.panSpeed += pan * 40;
        }

        /// <summary>
        /// 添加旋转
        /// </summary>
        /// <param name="dx"></param>
        /// <param name="dy"></param>
        public void AddRotateForce(double dx, double dy)
        {
            if (!AttachCamera.GetIsRotationEnabled(this))
            {
                return;
            }

            this.PushCameraSetting();
            this.rotationPoint3D = this.CameraTarget;
            this.rotationPosition = new Point(this.ActualWidth / 2, this.ActualHeight / 2);
            this.rotationSpeed.X += dx * 40;
            this.rotationSpeed.Y += dy * 40;
        }

        /// <summary>
        /// 添加缩放
        /// </summary>
        /// <param name="dx"></param>
        public void AddZoomForce(double dx)
        {
            this.AddZoomForce(dx, this.CameraTarget);
        }

        /// <summary>
        /// 添加缩放
        /// </summary>
        /// <param name="dx"></param>
        /// <param name="zoomOrigin"></param>
        public void AddZoomForce(double dx, Point3D zoomOrigin)
        {
            if (!AttachCamera.GetIsZoomEnabled(this))
            {
                return;
            }
            this.PushCameraSetting();
            this.zoomPoint3D = zoomOrigin;
            this.zoomSpeed += dx * 8;
        }

        /// <summary>
        /// 在指定位置显示目标装饰器
        /// </summary>
        /// <param name="position">位置</param>
        public void ShowTargetAdorner(Point position)
        {
            if (!AttachCamera.GetShowCameraTarget(this))
            {
                return;
            }

            if (this.targetAdorner != null)
            {
                return;
            }

            AdornerLayer myAdornerLayer = AdornerLayer.GetAdornerLayer(this.Viewport);
            this.targetAdorner = new TargetSymbolAdorner(this.Viewport, position);
            myAdornerLayer.Add(this.targetAdorner);
        }

        /// <summary>
        ///隐藏目标装饰器
        /// </summary>
        public void HideTargetAdorner()
        {
            AdornerLayer myAdornerLayer = AdornerLayer.GetAdornerLayer(this.Viewport);
            if (this.targetAdorner != null)
            {
                myAdornerLayer.Remove(this.targetAdorner);
            }

            this.targetAdorner = null;

            // the adorner sometimes leaves some 'dust', so refresh the viewport
            this.RefreshViewport();
        }

        /// <summary>
        /// 刷新3D视窗
        /// </summary>
        private void RefreshViewport()
        {
            // todo: this is a hack, should be improved

            // var mg = new ModelVisual3D { Content = new AmbientLight(Colors.White) };
            // Viewport.Children.Add(mg);
            // Viewport.Children.Remove(mg);
            Camera c = this.Viewport.Camera;
            this.Viewport.Camera = null;
            this.Viewport.Camera = c;

            // var w = Viewport.Width;
            // Viewport.Width = w-1;
            // Viewport.Width = w;

            // Viewport.InvalidateVisual();
        }

#if USE_RECTANGLE_SHAPE
        private Canvas rectangleCanvas;
        private Rectangle rectangleShape;

        public void RectangleShow(Rect rect)
        {
            this.rectangleShape = new Rectangle();
            this.rectangleShape.Width = rect.Width;
            this.rectangleShape.Height = rect.Height;
            this.rectangleShape.Stroke = Brushes.Red;
            this.rectangleShape.StrokeThickness = 1;
            Canvas.SetLeft(this.rectangleShape, rect.Left);
            Canvas.SetTop(this.rectangleShape, rect.Top);
            this.rectangleCanvas = new Canvas();
            this.rectangleCanvas.Children.Add(this.rectangleShape);
            this.Children.Add(this.rectangleCanvas);
        }
        public void RectangleUpdate(Rect rect)
        {
            this.rectangleShape.Width = rect.Width;
            this.rectangleShape.Height = rect.Height;
            Canvas.SetLeft(this.rectangleShape, rect.Left);
            Canvas.SetTop(this.rectangleShape, rect.Top);
        }
        public void RectangleHide()
        {
            this.rectangleCanvas.Children.Remove(this.rectangleShape);
            this.rectangleShape = null;
            Children.Remove(this.rectangleCanvas);
            this.rectangleCanvas = null;
        }
#else
        #region 矩形相关
        /// <summary>
        /// 显示矩形
        /// </summary>
        /// <param name="rect"></param>
        /// <param name="color1"></param>
        /// <param name="color2"></param>
        public void ShowRectangle(Rect rect, Color color1, Color color2)
        {
            if (this.rectangleAdorner != null)
            {
                return;
            }

            AdornerLayer myAdornerLayer = AdornerLayer.GetAdornerLayer(this.Viewport);
            this.rectangleAdorner = new RectangleAdorner(
                this.Viewport, rect, color1, color2, 3, 1, 10, DashStyles.Solid);
            myAdornerLayer.Add(this.rectangleAdorner);
        }

        /// <summary>
        /// 更新矩形
        /// </summary>
        /// <param name="rect"></param>
        public void UpdateRectangle(Rect rect)
        {
            if (this.rectangleAdorner == null)
            {
                return;
            }

            this.rectangleAdorner.Rectangle = rect;
            this.rectangleAdorner.InvalidateVisual();
        }

        /// <summary>
        /// 隐藏矩形
        /// </summary>
        public void HideRectangle()
        {
            AdornerLayer myAdornerLayer = AdornerLayer.GetAdornerLayer(this.Viewport);
            if (this.rectangleAdorner != null)
            {
                myAdornerLayer.Remove(this.rectangleAdorner);
            }

            this.rectangleAdorner = null;

            this.Viewport.InvalidateVisual();
        }
        #endregion
#endif

        /// <summary>
        /// 
        /// </summary>
        /// <param name="target"></param>
        /// <param name="animationTime"></param>
        [Obsolete]
        public void LookAt(Point3D target, double animationTime)
        {
            if (!AttachCamera.GetIsPanEnabled(this))
            {
                return;
            }
            this.PushCameraSetting();
            CameraHelper.LookAt(this.Camera, target, animationTime);
        } 
        #endregion
    }
}
